/**
 * 读取md文件，解析成html插入相关模板
 * @param readMdPath 
 * @param templatePath 
 * @returns 返回模板
 */
export function markdowm(readMdPath: string, templatePath: string): string {
  const Prism = require('node-prismjs');
  const marked = require('marked');
  const YFM = require('yaml-front-matter');
  const fs = require('fs');
  const remark = require('remark');
  const renderer = new marked.Renderer();
  const insideString = {
    variable: [
      // Arithmetic Environment
      {
        pattern: /\$?\(\([\w\W]+?\)\)/,
        inside: {
          // If there is a $ sign at the beginning highlight $(( and )) as variable
          variable: [{
            pattern: /(^\$\(\([\w\W]+)\)\)/,
            lookbehind: true
          },
            /^\$\(\(/,
          ],
          number: /\b-?(?:0x[\dA-Fa-f]+|\d*\.?\d+(?:[Ee]-?\d+)?)\b/,
          // Operators according to https://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic
          operator: /--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/,
          // If there is no $ sign at the beginning highlight (( and )) as punctuation
          punctuation: /\(\(?|\)\)?|,|;/
        }
      },
      // Command Substitution
      {
        pattern: /\$\([^)]+\)|`[^`]+`/,
        inside: {
          variable: /^\$\(|^`|\)$|`$/
        }
      },
      /\$(?:[a-z0-9_#\?\*!@]+|\{[^}]+\})/i
    ],
  };

  // 定义bash语言的样式
  Prism.languages.bash = {
    'shebang': {
      pattern: /^#!\s*\/bin\/bash|^#!\s*\/bin\/sh/,
      alias: 'important'
    },
    'comment': {
      pattern: /(^|[^"{\\])#.*/,
      lookbehind: true
    },
    'string': [
      //Support for Here-Documents https://en.wikipedia.org/wiki/Here_document
      {
        pattern: /((?:^|[^<])<<\s*)(?:"|')?(\w+?)(?:"|')?\s*\r?\n(?:[\s\S])*?\r?\n\2/g,
        lookbehind: true,
        greedy: true,
        inside: insideString
      },
      {
        pattern: /(["'])(?:\\\\|\\?[^\\])*?\1/g,
        greedy: true,
        inside: insideString
      }
    ],
    'variable': insideString.variable,
    // Originally based on http://ss64.com/bash/
    'function': {
      pattern: /(^|\s|;|\||&)(?:alias|keep-ui-vue|keep-ui-core|@angular\/cli|apropos|apt-get|aptitude|aspell|awk|basename|bash|bc|bg|builtin|bzip2|cal|cat|cd|cfdisk|chgrp|chmod|chown|chroot|chkconfig|cksum|clear|cmp|comm|command|cp|cron|crontab|csplit|cut|date|dc|dd|ddrescue|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|enable|env|ethtool|eval|exec|expand|expect|export|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|getopts|git|grep|groupadd|groupdel|groupmod|groups|gzip|hash|head|help|hg|history|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|jobs|join|kill|killall|less|link|ln|locate|logname|logout|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|make|man|mkdir|mkfifo|mkisofs|mknod|more|most|mount|mtools|mtr|mv|mmv|nano|netstat|nice|nl|nohup|notify-send|npm|ng|nslookup|open|op|passwd|paste|pathchk|ping|pkill|popd|pr|printcap|printenv|printf|ps|pushd|pv|pwd|quota|quotacheck|quotactl|ram|rar|rcp|read|readarray|readonly|reboot|rename|renice|remsync|rev|rm|rmdir|rsync|screen|scp|sdiff|sed|seq|service|sftp|shift|shopt|shutdown|sleep|slocate|sort|source|split|ssh|stat|strace|su|sudo|sum|suspend|sync|tail|tar|tee|test|time|timeout|times|touch|top|traceroute|trap|tr|tsort|tty|type|ulimit|umask|umount|unalias|uname|unexpand|uniq|units|unrar|unshar|uptime|useradd|userdel|usermod|users|uuencode|uudecode|v|vdir|vi|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yes|zip)(?=$|\s|;|\||&)/,
      lookbehind: true
    },
    'keyword': {
      pattern: /(^|\s|;|\||&)(?:let|:|\.|if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)(?=$|\s|;|\||&)/,
      lookbehind: true
    },
    'boolean': {
      pattern: /(^|\s|;|\||&)(?:true|false)(?=$|\s|;|\||&)/,
      lookbehind: true
    },
    'operator': /&&?|\|\|?|==?|!=?|<<<?|>>|<=?|>=?|=~/,
    'punctuation': /\$?\(\(?|\)\)?|\.\.|[{}[\];]/
  };

  const inside = insideString.variable[1].inside;
  inside['function'] = Prism.languages.bash['function'];
  inside.keyword = Prism.languages.bash.keyword;
  inside.boolean = Prism.languages.bash.boolean;
  inside.operator = Prism.languages.bash.operator;
  inside.punctuation = Prism.languages.bash.punctuation;

  renderer.heading = function (text, level) {
    const lowerText = text.toLowerCase().replace(/ /g, '-').replace(/\./g, '-').replace(/\?/g, '');
    const isMarkedLabel = (level === 3) && (text.indexOf('kp-') === 0);
    const isDirective = (text.indexOf('[') > -1) && (text.indexOf(']') > -1);
    const isComponent = isMarkedLabel && !isDirective;
    const isService = (text.indexOf('Kp') === 0) && (text.indexOf('Service') > -1);
    const head = `<h${level} id="${lowerText}"><span>${text}</span>`;
    const link = `<a onclick="window.location.hash = '${lowerText}'" class="anchor">#</a></h${level}>`;
    if (isComponent) {
      return head + `<label class="api-type-label component">component</label>` + link;
    } else if (isDirective) {
      return head + `<label class="api-type-label directive">directive</label>` + link;
    } else if (isService) {
      return head + `<label class="api-type-label service">service</label>` + link;
    } else {
      return head + link;
    }
  };

  marked.setOptions({
    highlight: function (code, lang) {
      const language = Prism.languages[lang] || Prism.languages.autoit;
      return Prism.highlight(code, language);
    },
    renderer: renderer
  });

  // 解析md流
  const meta = YFM.loadFront(fs.readFileSync(readMdPath));
  const content = meta.__content;
  const ast = remark.parse(content);

  // 分离前后两部分
  let isAfterAPIHeading = false;

  let firstPart = '';
  let secondPart = '';
  for (let i = 0; i < ast.children.length; i++) {
    const child = ast.children[i];
    if (child.type === 'heading' && child.depth === 2 && child.children[0].value === 'API') {
      isAfterAPIHeading = true;
    }
    if (!isAfterAPIHeading) {
      firstPart += marked(remark.stringify(child));
    } else {
      secondPart += marked(remark.stringify(child));
    }
  }
  const template = String(fs.readFileSync(templatePath));
  return template.replace(/{{firstPart}}/g, firstPart)
    .replace(/{{secondPart}}/g, secondPart);
}